package ocg.http.httpcore;

import ocg.common.re.Assertion;
import ocg.common.re.file.ReString;
import ocg.common.re.reports.ExtentManager;
import ocg.common.re.reports.ExtentTestNGReportBuilder;
import ocg.common.re.reports.TestReport;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * Created by chenbo on 2018/4/25.
 */
public class HttpFactory {

    private static Logger logger = LogManager.getLogger ( HttpFactory.class );
    private static TestReport apiReport;
    private static CloseableHttpClient httpClient = null;

    /**
     * 请求代理设置
     * @param host                  代理 IP
     * @param port              代理 端口号
     * @param schema          代理 协议类型
     */
    public HttpFactory( String host , int port , String schema ){
        //设置代理IP、端口、协议（请分别替换）
        HttpHost proxy = new HttpHost ( host,port,schema );

        //把代理设置到请求配置
        RequestConfig defaultRequestConfig = RequestConfig.custom()
                .setProxy(proxy)
                .build();

        HttpFactory.httpClient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();

    }

    /**
     * 判断 HttpModel.getModel 合适的请求方式
     * @param  model        http 请求模型
     * @return HttpResponse
     */
    public static HttpResponse factory( HttpModel model ){

        if ( HttpFactory.httpClient == null) {
            HttpFactory.httpClient = HttpClientBuilder.create().build();
        }

        apiReport = new TestReport( Assertion.get().get() , model.getUrl () ,"@A");

        CloseableHttpResponse httpResponse = null;

        if ( model.getModel ().equals ( "get" )){
            httpResponse = httpGet(model);
        }else if ( model.getModel ().equals ( "post" ) ){
            httpResponse = httpPost(model);
        }

        if ( httpResponse != null) {
            logger.debug (  "response-line: " + httpResponse.getStatusLine () );
            apiReport.log_info("response-line:" , httpResponse.getStatusLine ().toString());
            return new HttpResponse ( httpResponse , apiReport );
        }else {
            logger.error ( "接口请求失败！" );
            apiReport.log_error("失败:","接口请求失败！");
        }

        return null;
    }

    /**
     * post 请求
     * @param model     http 请求模型
     * @return
     */
    private static CloseableHttpResponse httpPost(HttpModel model) {

        CloseableHttpResponse httpResponse = null;

        URI uri = geturl ( model.getUrl () );

        if ( model != null && uri != null ) {

            HttpPost post = new HttpPost( uri );

            if ( model.getHeaders ().size () >0 ) {
                for ( String key : model.getHeaders ().keySet() ){
                    logger.debug ( "request-header: " + key + " : " + model.getHeaders ().get( key ) );
                    post.setHeader( key , model.getHeaders ().get( key ));
                }
            }

            apiReport.log_info("request-header:",model.getHeaders ());

            if ( model.getCookies ().size ()>0) {
                post.setHeader ( "Cookie" , getCookies ( model.getCookies () ) );
            }
            apiReport.log_info("request-cookies:",model.getCookies ());

            logger.debug ( "request-line: " + post.getRequestLine () );
            apiReport.log_info("request-line:", post.getRequestLine ().toString());
            /*
             * 两种设置 body 的方式：
             * String 和 参数
             */
            if ( model.getBody () != null) {
                try {

                    post.setEntity(  new StringEntity ( model.getBody () ));

                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                logger.debug ("request-body:\n" + model.getBody () );
                apiReport.log_info_Code("request-body:" , model.getBody ());
            } else if ( model.getParameters ().size ()>0) {
                //设置参数
                List<NameValuePair> parm = new ArrayList <> ();
                for ( String key : model.getParameters ().keySet() ){
                    parm.add ( new BasicNameValuePair ( key, model.getParameters ().get( key ) ));
                }
                try {
                    post.setEntity(new UrlEncodedFormEntity ( parm, HTTP.UTF_8));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace ();
                }
                logger.debug ("request-body:\n" + model.getParameters () );
                apiReport.log_info ("request-body:" , model.getParameters ());
            }



            try {

                httpResponse = httpClient.execute( post );

            } catch (IOException e) {
                e.printStackTrace ();
            }

        }
        return httpResponse;
    }

    /**
     * http get 请求
     * @param model         http 请求模型
     * @return
     */
    private static CloseableHttpResponse httpGet( HttpModel model ){

        CloseableHttpResponse httpResponse = null;



        if ( model != null && model.getUrl () != null ) {

            List<NameValuePair> parameters = new  ArrayList<>();

            if ( model.getParameters ().size ()>0) {

                for (String s : model.getParameters ().keySet ()) {
                    parameters.add ( new BasicNameValuePair ( s , model.getParameters ().get ( s ) ) );
                }

            }

            URI uri = UrlParameters( model.getUrl () , parameters );
            if (uri != null) {

                    HttpGet get = new HttpGet ( uri );

                    if ( model.getHeaders ().size () > 0) {
                        for ( String key : model.getHeaders ().keySet() ){
                            logger.debug ( "request-header: " + key + " : " + model.getHeaders ().get( key ) );
                            get.setHeader( key , model.getHeaders ().get( key ) );
                        }
                    }

                    apiReport.log_info("request-header: ",model.getHeaders ());

                    if ( model.getCookies ().size () >0 ) {
                        get.setHeader ( "Cookie" , getCookies ( model.getCookies () ) );
                    }

                    apiReport.log_info("request-Cookie: ",model.getCookies ());

                    logger.debug ( "Request-line: " + get.getRequestLine () );
                    apiReport.log_info("Request-line: " , get.getRequestLine ().toString());
                    try {
                        httpResponse = httpClient.execute( get );
                    } catch (IOException e) {
                        e.printStackTrace ();
                    }
            }else{
                logger.error ( "请求链接不能空" );
                apiReport.log_error("失败：","请求链接不能空");
            }

        }

        return httpResponse;
    }

    /**
     * @param map       cookies
     * @return
     */
    public static String getCookies(Map<String,String> map){
        String cookies = "";

        for ( String s : map.keySet ()) {
            cookies = cookies + s + "=" + map.get ( s ) + ";";
        }
        return cookies;
    }

    /**
     * 返回完整Url链接
     * @param url                   url 域名
     * @param parameters            请求参数
     * @return
     */
    public static URI UrlParameters( String url , List<NameValuePair> parameters ){

        if ( ReString.isBlank(url) ) {
            return null;
        }

        try {
            URIBuilder uriBuilder = absHost ( url );

            List<NameValuePair> nvps = uriBuilder.getQueryParams();
            nvps.removeAll( parameters );
            nvps.addAll( parameters );
            uriBuilder.setParameters(nvps);

            return uriBuilder.build ();

        } catch (URISyntaxException e) {
                e.printStackTrace();
        }

        return null;
    }

    /**
     * 获取 Url 不添加参数
     * @param url           url 请求链接
     * @return
     */
    public static URI geturl(String url){

        if ( ReString.isBlank(url) ) {
            return null;
        }

        URIBuilder uriBuilder = absHost ( url );

        if (uriBuilder != null) {
            try {

                return uriBuilder.build ();

            } catch (URISyntaxException e) {
                e.printStackTrace ();
            }
        }

        return null;
    }

    /**
     * 判断链接是否完成，添加默认的域名
     * @param url           url 请求链接
     * @return
     */
    public static URIBuilder absHost( String url ){

        try {
            URIBuilder uriBuilder = new URIBuilder ( url );

            if ( uriBuilder.getHost () == null) {
                uriBuilder.setScheme( Basic.getScheme ());

                if ( Basic.getPart () > 0 ){
                    uriBuilder.setHost ( Basic.getIp () )
                            .setPort ( Basic.getPart () );
                }else {
                    uriBuilder.setHost ( Basic.getHost () );
                }

            }

            return uriBuilder;

        } catch (URISyntaxException e) {
            e.printStackTrace ();
        }
        return null;
    }
}
